#pragma once

#include <Hittable.hpp>
#include <Ray.hpp>

class Material {
 public:
  virtual ~Material() = default;

  virtual bool Scatter(const Ray& ray, const HitRecord& rec,
                       glm::vec3& attenuation, Ray& scattered) const = 0;
};

class Lambertian : public Material {
 public:
  Lambertian(glm::vec3 albedo) : Material(), mAlbedo(std::move(albedo)) {}
  ~Lambertian() override = default;

  bool Scatter(const Ray& ray, const HitRecord& rec, glm::vec3& attenuation,
               Ray& scattered) const override;

 private:
  glm::vec3 mAlbedo;
};

class Metal : public Material {
 public:
  Metal(glm::vec3 albedo) : Material(), mAlbedo(albedo) {}
  Metal(glm::vec3 albedo, float fuzz)
      : Material(), mAlbedo(albedo), mFuzz(glm::max(1.f, fuzz)) {}

  ~Metal() override = default;

  bool Scatter(const Ray& ray, const HitRecord& rec, glm::vec3& attenuation,
               Ray& scattered) const override;

 private:
  glm::vec3 mAlbedo;
  float mFuzz = 0.f;
};

class Dielectric : public Material {
 public:
  Dielectric(float index_of_refraction)
      : Material(), mIR(index_of_refraction) {}
  ~Dielectric() override = default;

  bool Scatter(const Ray& ray, const HitRecord& rec, glm::vec3& attenuation,
               Ray& scattered) const override;

 private:
  // Index of Refraction
  float mIR;
};
